﻿
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using System;
namespace DX
{
    public class CacheProvider : ICacheProvider
    {

        public CacheProvider(IDistributedCache cache, IBufferSerializeProvider serializeProvider, ILogger<CacheProvider> logger)
        {
            this.cache = cache;
            this.serializeProvider = serializeProvider;
            this.logger = logger;
        }
        private readonly IDistributedCache cache;
        private readonly IBufferSerializeProvider serializeProvider;
        private readonly ILogger logger;

        public bool TryGet<T>(string key, out T value)
        {
            var buffer = cache.Get(key);
            if (buffer == null)
            {
                value = default(T);
                return false;
            }
            try
            {
                value = serializeProvider.Deserialize<T>(buffer);

                return true;
            }
            catch (Exception ex)
            {
                logger.LogError(ex, " serialize");

            }
            value = default(T);
            return false;
        }
        public T GetOrAdd<T>(string key, Func<T> func)
        {

            return GetValue(key, func, val =>
            {
                var buffer = serializeProvider.Serialize(val);
                cache.Set(key, buffer);
            });

        }

        private T GetValue<T>(string key, Func<T> func, Action<T> setCache)
        {
            var buffer = cache.Get(key);
            try
            {
                if (buffer != null)
                {
                    return serializeProvider.Deserialize<T>(buffer);
                }
            }
            catch (Exception ex)
            {

                logger.LogError(ex, " serialize");
            }

            T val = func();
            setCache(val);
            return val;
        }

        public T GetOrAdd<T>(string key, Func<T> func, TimeSpan expiration)
        {
            return GetValue(key, func, val =>
            {
                Set(key, val, expiration);

            });


        }

        public T GetOrAddSliding<T>(string key, Func<T> func, TimeSpan expiration)
        {
            return GetValue(key, func, val =>
            {
                SetSliding(key, val, expiration);
            });


        }
        public void Set(string key, object value)
        {
            if (value == null)
            {
                cache.Remove(key);
                return;
            }
            var buffer = serializeProvider.Serialize(value);
            cache.Set(key, buffer);
        }

        public void Set(string key, object value, TimeSpan expiration)
        {
            if (value == null)
            {
                cache.Remove(key);
                return;
            }
            var buffer = serializeProvider.Serialize(value);
            cache.Set(key, buffer, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration });

        }

        public void SetSliding(string key, object value, TimeSpan expiration)
        {
            if (value == null)
            {
                cache.Remove(key);
                return;
            }
            var buffer = serializeProvider.Serialize(value);
            cache.Set(key, buffer, new DistributedCacheEntryOptions { SlidingExpiration = expiration });

        }


    }


}